package com.monkey.core.plugin.code.tpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.monkey.core.plugin.dto.MonkeyDto;
import com.monkey.core.plugin.velocity.VelocityHelper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Project  : monkey
 * Author   : Wu Tian Qiang
 * Date     : 2016/9/7
 */
public abstract class AbstractCodeTemplateGenerator implements CodeTemplateGenerator {
    protected static final String CORE_JAVA_PATH = "/monkey-core/src/main/java/";
    protected static final String VIEW_PATH = "/monkey-static/";
    protected static final String WEB_JAVA_PATH = "/monkey-web/src/main/java/";
    protected static final String DATE_FORMAT = "yyyMMddHHmmss";

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void generate(MonkeyDto monkeyDto) {
        JSONObject files = JSON.parseObject(monkeyDto.getString("files"));
        if ("on".equals(files.getString("isDomain"))) {
            generateDomain(monkeyDto);
        }
        if ("on".equals(files.getString("isRepository"))) {
            generateRepository(monkeyDto);
        }
        if ("on".equals(files.getString("isController"))) {
            generateController(monkeyDto);
        }
        if ("on".equals(files.getString("isService"))) {
            generateService(monkeyDto);
        }
        if ("on".equals(files.getString("isView"))) {
            generateView(monkeyDto);
        }
    }

    /**
     * 准备公用参数
     *
     * @param monkeyDto
     */
    protected Map<String, Object> getCommonParams(MonkeyDto monkeyDto) {
        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        Map<String, Object> commonParams = new HashMap<>();
        commonParams.put("projectPath", monkeyDto.getString("projectPath"));
        commonParams.put("codeGenerator", monkeyDto.getString("codeGenerator"));
        commonParams.put("entityIdType", monkeyDto.getString("entityIdType"));
        commonParams.put("modulePath", getJavaModulePath(monkeyDto));
        commonParams.put("createDate", DateFormatUtils.format(new Date(), "yyyy/MM/dd HH:mm:ss"));
        commonParams.put("package", modelParams.getString("basePath").replaceAll("/", "."));
        return commonParams;
    }

    /**
     * 获取模块的路径
     *
     * @param monkeyDto
     * @return
     */
    protected String getJavaModulePath(MonkeyDto monkeyDto) {
        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        return monkeyDto.getString("projectPath") +
                WEB_JAVA_PATH +
                modelParams.getString("basePath") + "/" +
                modelParams.getString("moduleName");
    }

    /**
     * 获取View的视图地址
     *
     * @param monkeyDto
     * @return
     */
    protected String getViewModulePath(MonkeyDto monkeyDto) {
        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        return monkeyDto.getString("projectPath") + VIEW_PATH +
                "classic/src/view/" + modelParams.getString("moduleName");
    }

    protected String getStoreModulePath(MonkeyDto monkeyDto) {
        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        return monkeyDto.getString("projectPath") + VIEW_PATH + "app/store/"
                + modelParams.getString("moduleName");
    }

    protected String getModelModulePath(MonkeyDto monkeyDto) {
        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        return monkeyDto.getString("projectPath") + VIEW_PATH + "app/model/"
                + modelParams.getString("moduleName");
    }


    /**
     * 生成Service
     *
     * @param monkeyDto
     */
    protected void generateService(MonkeyDto monkeyDto) {
        logger.info("正在生成Service......");
        JSONObject modelParams = prepareServiceParams(monkeyDto);

        String directory = getJavaModulePath(monkeyDto) + "/service";

        StringWriter writer = VelocityHelper.mergeFileTemplate(getServiceTemplate(), modelParams);
        String fileName = modelParams.getString("className") + "Service.java";
        saveStringToFile(directory, fileName, writer.toString());

        StringWriter writer2 = VelocityHelper.mergeFileTemplate(getServiceImplTemplate(), modelParams);
        String fileName2 = modelParams.getString("className") + "ServiceImpl.java";
        saveStringToFile(directory, fileName2, writer2.toString());

        logger.info("生成Service完成......");
    }

    protected abstract JSONObject prepareServiceParams(MonkeyDto monkeyDto);

    protected abstract String getServiceImplTemplate();

    protected abstract String getServiceTemplate();

    /**
     * 生成View
     *
     * @param monkeyDto
     */
    protected void generateView(MonkeyDto monkeyDto) {
        logger.info("正在生成View......");
        JSONObject params = prepareViewParams(monkeyDto);
        String viewDirectory = getViewModulePath(monkeyDto);
        String storeDirectory = getStoreModulePath(monkeyDto);
        String modelModulePath = getModelModulePath(monkeyDto);
        //view
        StringWriter viewWriter = VelocityHelper.mergeFileTemplate(getViewTemplate(), params);
        String viewFileName = params.getString("className") + ".js";
        saveStringToFile(viewDirectory, viewFileName, viewWriter.toString());
        //controller
        StringWriter controllerWriter = VelocityHelper.mergeFileTemplate(getViewControllerTemplate(), params);
        String ctrlFileName = params.getString("className") + "Controller.js";
        saveStringToFile(viewDirectory, ctrlFileName, controllerWriter.toString());
        //store
        StringWriter storeWriter = VelocityHelper.mergeFileTemplate(getStoreControllerTemplate(), params);
        String storeFileName = params.getString("className") + ".js";
        saveStringToFile(storeDirectory, storeFileName, storeWriter.toString());
        //model
        StringWriter modelWriter = VelocityHelper.mergeFileTemplate(getModelControllerTemplate(), params);
        String modelFileName = params.getString("className") + ".js";
        saveStringToFile(modelModulePath, modelFileName, modelWriter.toString());
        //viewmodel
        StringWriter viewModelWriter = VelocityHelper.mergeFileTemplate(getViewModelControllerTemplate(), params);
        String viewModelFileName = params.getString("className") + "Model.js";
        saveStringToFile(viewDirectory, viewModelFileName, viewModelWriter.toString());

        //window
        StringWriter windowWriter = VelocityHelper.mergeFileTemplate(getWindowControllerTemplate(), params);
        String windowFileName = params.getString("className") + "Window.js";
        saveStringToFile(viewDirectory, windowFileName, windowWriter.toString());


        logger.info("生成View完成......");
    }

    protected abstract String getWindowControllerTemplate();

    protected abstract String getViewModelControllerTemplate();

    protected abstract String getModelControllerTemplate();

    protected abstract String getStoreControllerTemplate();

    protected abstract String getViewControllerTemplate();

    protected abstract String getViewTemplate();

    protected abstract JSONObject prepareViewParams(MonkeyDto monkeyDto);

    /**
     * 生成Controller
     *
     * @param monkeyDto
     */
    protected void generateController(MonkeyDto monkeyDto) {
        logger.info("正在生成Controller......");
        JSONObject params = prepareControllerParams(monkeyDto);

        StringWriter writer = VelocityHelper.mergeFileTemplate(getControllerTemplate(), params);
        String directory = getJavaModulePath(monkeyDto) + "/controller";
        String fileName = params.getString("className") + "Controller.java";

        saveStringToFile(directory, fileName, writer.toString());
        logger.info("生成Controller完成......");
    }

    protected abstract String getControllerTemplate();

    protected abstract JSONObject prepareControllerParams(MonkeyDto monkeyDto);

    /**
     * 生成Repository
     *
     * @param monkeyDto
     */
    protected void generateRepository(MonkeyDto monkeyDto) {
        logger.info("正在生成Repository......");
        JSONObject modelParams = prepareRepositoryParams(monkeyDto);

        StringWriter writer = VelocityHelper.mergeFileTemplate(getRepositoryTemplate(), modelParams);
        String directory = getJavaModulePath(monkeyDto) + "/domain";
        String fileName = modelParams.getString("className") + "Repository.java";

        saveStringToFile(directory, fileName, writer.toString());
        logger.info("生成Repository完成......");
    }

    protected abstract String getRepositoryTemplate();

    protected abstract JSONObject prepareRepositoryParams(MonkeyDto monkeyDto);

    /**
     * 生成model
     *
     * @param monkeyDto
     */
    protected void generateDomain(MonkeyDto monkeyDto) {
        logger.info("正在生成Domain......");

        Map<String, Object> params = prepareDomainParams(monkeyDto);
        StringWriter writer = VelocityHelper.mergeFileTemplate(getDomainTemplate(), params);

        JSONObject modelParams = JSON.parseObject(monkeyDto.getString("modelParam"));
        String directory = getJavaModulePath(monkeyDto) + "/domain";
        String fileName = modelParams.getString("className") + ".java";

        saveStringToFile(directory, fileName, writer.toString());
        logger.info("生成Domain完成......");
    }

    protected abstract String getDomainTemplate();

    protected abstract Map<String, Object> prepareDomainParams(MonkeyDto monkeyDto);


    /**
     * 如果文件已经存在就重命名文件
     *
     * @param fileName 文件名
     * @param content  文件内容
     */
    protected void saveStringToFile(String directory, String fileName, String content) {
        try {
            File file = new File(directory, fileName);
            if (file.exists()) {
                String newFileName = fileName + DateFormatUtils.format(new Date(), DATE_FORMAT);
                logger.info("文件名称已经存在，重命名文件，新名称{}", newFileName);
                file.renameTo(new File(directory, newFileName));
            }
            FileUtils.forceMkdir(new File(directory));
            FileOutputStream fos = new FileOutputStream(new File(directory, fileName));
            OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
            out.write(content);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
